import mongoose, { Document, Schema } from 'mongoose';
import bcrypt from 'bcryptjs';

// 用户接口定义
export interface IUser extends Document {
  username: string;
  email: string;
  phone?: string;
  password_hash: string;
  real_name?: string;
  avatar?: string;
  gender?: 'male' | 'female' | 'other';
  birth_date?: Date;
  address?: string;
  is_verified: boolean;
  status: 'active' | 'inactive' | 'banned';
  created_at: Date;
  updated_at: Date;
  
  // 实例方法
  comparePassword(password: string): Promise<boolean>;
  toJSON(): any;
}

// 用户创建接口
export interface IUserCreate {
  username: string;
  email: string;
  password: string; // 明文密码
  phone?: string;
  real_name?: string;
  avatar?: string;
  gender?: 'male' | 'female' | 'other';
  birth_date?: Date;
  address?: string;
}

// 用户Schema定义
const userSchema = new Schema<IUser>({
  username: {
    type: String,
    required: [true, '用户名是必需的'],
    unique: true,
    trim: true,
    minlength: [3, '用户名至少3个字符'],
    maxlength: [50, '用户名最多50个字符'],
    match: [/^[a-zA-Z0-9_]+$/, '用户名只能包含字母、数字和下划线']
  },
  email: {
    type: String,
    required: [true, '邮箱是必需的'],
    unique: true,
    trim: true,
    lowercase: true,
    match: [/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, '邮箱格式不正确']
  },
  phone: {
    type: String,
    unique: true,
    sparse: true,
    match: [/^1[3-9]\d{9}$/, '手机号格式不正确']
  },
  password_hash: {
    type: String,
    required: [true, '密码是必需的'],
    minlength: [6, '密码至少6个字符']
  },
  real_name: {
    type: String,
    trim: true,
    maxlength: [50, '真实姓名最多50个字符']
  },
  avatar: {
    type: String,
    validate: {
      validator: function(v: string) {
        return /^https?:\/\/.+/.test(v);
      },
      message: '头像必须是有效的URL'
    }
  },
  gender: {
    type: String,
    enum: {
      values: ['male', 'female', 'other'],
      message: '性别只能是 male, female 或 other'
    }
  },
  birth_date: {
    type: Date,
    validate: {
      validator: function(v: Date) {
        return v <= new Date();
      },
      message: '出生日期不能是未来时间'
    }
  },
  address: {
    type: String,
    maxlength: [500, '地址最多500个字符']
  },
  is_verified: {
    type: Boolean,
    default: false
  },
  status: {
    type: String,
    enum: {
      values: ['active', 'inactive', 'banned'],
      message: '状态只能是 active, inactive 或 banned'
    },
    default: 'active'
  }
}, {
  timestamps: { 
    createdAt: 'created_at', 
    updatedAt: 'updated_at' 
  },
  toJSON: { 
    transform: function(doc, ret) {
      delete ret.password_hash;
      return ret;
    }
  },
  toObject: { 
    transform: function(doc, ret) {
      delete ret.password_hash;
      return ret;
    }
  }
});

// 索引
userSchema.index({ username: 1 });
userSchema.index({ email: 1 });
userSchema.index({ phone: 1 });
userSchema.index({ status: 1 });
userSchema.index({ created_at: -1 });

// 实例方法
userSchema.methods.comparePassword = async function(password: string): Promise<boolean> {
  return bcrypt.compare(password, this.password_hash);
};

userSchema.methods.toJSON = function(): any {
  const user = this.toObject();
  delete user.password_hash;
  return user;
};

// 中间件 - 保存前加密密码
userSchema.pre('save', async function(next) {
  // 只有在密码被修改时才重新加密
  if (!this.isModified('password_hash')) {
    return next();
  }
  
  try {
    const salt = await bcrypt.genSalt(10);
    this.password_hash = await bcrypt.hash(this.password_hash, salt);
    next();
  } catch (error) {
    next(error as Error);
  }
});

// 中间件 - 更新前加密密码
userSchema.pre('findOneAndUpdate', async function(next) {
  const update = this.getUpdate() as any;
  
  if (update.password_hash) {
    try {
      const salt = await bcrypt.genSalt(10);
      update.password_hash = await bcrypt.hash(update.password_hash, salt);
    } catch (error) {
      return next(error as Error);
    }
  }
  
  next();
});

// 静态方法
userSchema.statics.findByUsername = function(username: string) {
  return this.findOne({ username });
};

userSchema.statics.findByEmail = function(email: string) {
  return this.findOne({ email });
};

userSchema.statics.findByPhone = function(phone: string) {
  return this.findOne({ phone });
};

// 创建并导出模型
const User = mongoose.model<IUser>('User', userSchema);

export default User; 